name: Create new release

on:
  workflow_dispatch:
    inputs:
      note:
        description: Release notes
        required: true
        type: string
      kind:
        description: 'Release kind (major, minor, patch)'
        required: true
        type: choice
        options:
          - major
          - minor
          - patch
        default: patch

jobs:
  release:
    runs-on: ubuntu-22.04
    permissions:
      contents: write
      packages: write
      pull-requests: write
    steps:
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - name: Get latest release
        id: get_latest_release
        run: |
          TAG=$(gh api /repos/${{ github.repository }}/releases/latest -q .tag_name)
          echo tag=$TAG >>$GITHUB_OUTPUT
        env:
          GH_TOKEN: ${{ github.token }}
      - name: Generate new version
        id: generate_new_version
        run: |
          semver() { curl -sL https://github.com/fsaintjacques/semver-tool/raw/3.4.0/src/semver | bash -s - "$@"; }
          VER=$(semver bump ${{ inputs.kind }} ${{ steps.get_latest_release.outputs.tag }})
          echo version=$VER >>$GITHUB_OUTPUT
      - name: Make tags for Docker images
        id: make_images_tags
        run: |
          IMAGE=${GITHUB_REPOSITORY@L}

          echo master=ghcr.io/$IMAGE:master >>$GITHUB_OUTPUT
          echo ver-master=ghcr.io/$IMAGE:${{ steps.generate_new_version.outputs.version }}-master >>$GITHUB_OUTPUT
          echo worker=ghcr.io/$IMAGE:worker >>$GITHUB_OUTPUT
          echo ver-worker=ghcr.io/$IMAGE:${{ steps.generate_new_version.outputs.version }}-worker >>$GITHUB_OUTPUT
      - name: Create release
        id: create_release
        run: |
          set -euxo pipefail

          BRANCH=release/$VER

          gh api --method POST /repos/${{ github.repository }}/git/refs \
            -f ref=refs/heads/$BRANCH \
            -f sha=$GITHUB_SHA

          sed_file() {
            local file="$1"
            local expr="$2"

            local sha="$(git rev-parse @:$file)"

            gh api --method PUT /repos/${{ github.repository }}/contents/$file \
              -f message="Update $file" \
              -f content="$(sed -E "$expr" "$file" | base64 -w0)" \
              -f branch=$BRANCH \
              -f sha="$sha"
          }

          sed_file deployment/master/deployment.yml \
            "s~^(.+): .+ (# MASTER IMAGE)~\1: ${{ steps.make_images_tags.outputs.ver-master }} \2~"

          sed_file deployment/worker/daemonset.yml \
            "s~^(.+): .+ (# WORKER IMAGE)~\1: ${{ steps.make_images_tags.outputs.ver-worker }} \2~"

          sed_file pkg/front/package.json \
            "s~^(.+\"version\":.+\").+(\".+)$~\1${{ steps.generate_new_version.outputs.version }}\2~"

          PR=$(gh api --method POST /repos/${{ github.repository }}/pulls \
            -f title="Release $VER" \
            -f head=$BRANCH \
            -f base=${{ github.event.repository.default_branch }} -q .number)

          gh api --method PUT /repos/${{ github.repository }}/pulls/$PR/merge \
            -f commit_title="Release $VER (#$PR)" \
            -f merge_method=squash

          gh api --method DELETE /repos/${{ github.repository }}/git/refs/heads/$BRANCH

          git pull
          
          echo "rev=$(git rev-parse @)" >>$GITHUB_OUTPUT
        env:
          GH_TOKEN: ${{ github.token }}
          VER: ${{ steps.generate_new_version.outputs.version }}
      - name: Create new release tag
        id: create_new_release_tag
        run: |
          TAG=v$VER

          gh api --method POST /repos/${{ github.repository }}/git/tags \
            -f tag=$TAG \
            -f message="Release $VER" \
            -f type=commit \
            -f object=${{ steps.create_release.outputs.rev }}
          
          gh api --method POST /repos/${{ github.repository }}/git/refs \
            -f ref=refs/tags/$TAG \
            -f sha=${{ steps.create_release.outputs.rev }}

          git fetch --tags
          
          echo tag=$TAG >>$GITHUB_OUTPUT
        env:
          GH_TOKEN: ${{ github.token }}
          VER: ${{ steps.generate_new_version.outputs.version }}
      - name: Generate changelog
        id: generate_changelog
        uses: mathiasvr/command-output@v2.0.0
        with:
          run: |
            echo -ne "${{ inputs.note }}\n\n"
            echo -ne "# Changelog: \n\n"
            { git log --pretty=format:"%H %s" $PREV..$NEXT~1; echo; } | tac
        env:
          PREV: ${{ steps.get_latest_release.outputs.tag }}
          NEXT: ${{ steps.create_new_release_tag.outputs.tag }}
      - name: Prepare metadata for Docker images
        id: prepare_image_meta
        uses: docker/metadata-action@v5
        with:
          labels: |
            org.opencontainers.image.title=WebK8S
            org.opencontainers.image.revision=${{ steps.create_release.outputs.rev }}
            org.opencontainers.image.version=${{ steps.generate_new_version.outputs.version }}
            org.opencontainers.image.licenses=LicenseRef-webk8s-eula
      - name: Build and push master Docker image
        uses: docker/build-push-action@v5
        with:
          target: master
          push: true
          tags: |
            ${{ steps.make_images_tags.outputs.master }}
            ${{ steps.make_images_tags.outputs.ver-master }}
          labels: ${{ steps.prepare_image_meta.outputs.labels }}
          annotations: ${{ steps.prepare_image_meta.outputs.annotations }}
          build-args: |
            VERSION=${{ steps.generate_new_version.outputs.version }}
      - name: Build and push worker Docker image
        uses: docker/build-push-action@v5
        with:
          target: worker
          push: true
          tags: |
            ${{ steps.make_images_tags.outputs.worker }}
            ${{ steps.make_images_tags.outputs.ver-worker }}
          labels: ${{ steps.prepare_image_meta.outputs.labels }}
          annotations: ${{ steps.prepare_image_meta.outputs.annotations }}
          build-args: |
            VERSION=${{ steps.generate_new_version.outputs.version }}
      - name: Export Docker images to tarballs
        run: |
          mkdir ./artifacts

          docker pull $MASTER
          docker pull $WORKER

          make_artifact_name() { cut -d: -f2- | tr - ' ' | awk '{print "webk8s-"$2"-"$1".tar"}'; }

          docker save $MASTER -o ./artifacts/"$(echo -n $MASTER | make_artifact_name)"
          docker save $WORKER -o ./artifacts/"$(echo -n $WORKER | make_artifact_name)"
        env:
          MASTER: ${{ steps.make_images_tags.outputs.ver-master }}
          WORKER: ${{ steps.make_images_tags.outputs.ver-worker }}
      - name: Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: Docker Images
          path: artifacts/*
      - name: Publish release
        uses: ncipollo/release-action@v1
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          name: WebK8S ${{ steps.generate_new_version.outputs.version }}
          tag: ${{ steps.create_new_release_tag.outputs.tag }}
          artifacts: artifacts/*
          body: ${{ steps.generate_changelog.outputs.stdout }}
          makeLatest: true
          artifactErrorsFailBuild: true
          draft: false
          prerelease: false
